/*
  Copyright (c) 2002, 2003 Russell Morris
  All rights reserved.

  Redistribution and use in source and binary forms, with or without modification, 
  are permitted provided that the following conditions are met:

    * Redistributions of source code must retain the above copyright notice, 
      this list of conditions and the following disclaimer. 
      
    * Redistributions in binary form must reproduce the above copyright notice, 
      this list of conditions and the following disclaimer in the documentation 
      and/or other materials provided with the distribution. 
      
    * The names of the contributors may not be used to endorse or promote 
      products derived from this software without specific prior written permission. 
      
    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
    AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
    IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
    ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 
    LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
    CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 
    SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
    INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER 
    IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
    ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 
    THE POSSIBILITY OF SUCH DAMAGE.
*/

using System;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;

namespace WRM.Windows.Forms
{
    /// <summary>
    /// <c>PaneNode</c> contains all information necessary to uniquely identify a
    /// conceptual node in a <see cref="PropertyTree"/>.
    /// </summary>
    /// <remarks>
    /// <para>
    /// Because of <see cref="SharedPropertyPane"/>s, <see cref="PropertyPane"/>s 
    /// do not necessarily contain all the information necessary to identify 
    /// themselves uniquely in the <see cref="PropertyTree"/>.  This is simply 
    /// because there is a 1-to-N relationship between an instance of a 
    /// <see cref="SharedPropertyPane"/> and nodes in the 
    /// <see cref="PropertyTree"/>.
    /// </para>
    /// <para>
    /// A <c>PaneNode</c> represents a single conceptual node in the 
    /// <see cref="PropertyTree"/>.  A <c>PaneNode</c> may or may not represent a 
    /// <see cref="SharedPropertyPane"/> descendant - it doesn't matter.  The 
    /// <c>PaneNode</c> keeps all of the information like <see cref="Index"/>, 
    /// <see cref="ImageIndex"/>, etc... so that the various descendants of 
    /// <see cref="PropertyPane"/> and <see cref="SharedPropertyPane"/> don't 
    /// have to keep up with these things.
    /// </para>
    /// <para>
    /// In addition to these duties, a <c>PaneNode</c> also keeps track of 
    /// all its child <c>PaneNode</c>s via its <see cref="PaneNode.PaneNodes"/> property.  
    /// Any  <c>PaneNode</c> objects that are members of this collection will 
    /// appear as children of this <c>PaneNode</c> in the <see cref="PropertyTree"/>.
    /// </para>
    /// </remarks>
    public class PaneNode : IComparable
    {
        private object mPaneInstanceData;
        private PropertyPane mPropertyPane;
        private Type mSharedPaneType;
        private bool mbIsShared;
        private int mIndex;
        private int mImageIndex;
        private int mSelectedImageIndex;
        private bool mExpanded;
        private string mText;
        private TreeNode mTreeNode;
        private bool mIsDummy;

        private PropertyTree mPropertyTree;
        private PaneNode mParent;
        private PaneNodeCollection mNodes;

        /// <summary>
        /// Constructs a <c>PaneNode</c> that is used as the root-level
        /// <c>PaneNode</c> for the given <see cref="PropertyTree"/>.
        /// </summary>
        /// <param name="grandPooBah">
        /// The <see cref="PropertyTree">PropertyTree</see> that will use
        /// this <c>PaneNode</c> as its root.
        /// </param>
        /// <remarks>
        /// <para>
        /// This constructor is marked <c>internal</c> because it only
        /// exists to facilitate the generic machinery of 
        /// <see cref="PropertyTree">PropertyTree</see>.
        /// </para>
        /// </remarks>
        internal PaneNode(PropertyTree grandPooBah)
        {
            mPropertyTree = grandPooBah;
            mPropertyPane = null;
            mbIsShared = false;
            mText = "";
            mNodes = new PaneNodeCollection(this);
        }

        /// <summary>
        /// Constructs a dummy <c>PaneNode</c>, used only in 
        /// <see cref="PropertyPane">PropertyPane</see>'s 
        /// <see cref="PropertyPane.PropertyPane"> constructor</see> to stash
        /// panes during build time.
        /// </summary>
        /// <remarks>
        /// This constructor is marked <c>internal</c> because it only exists
        /// to facilitate the generic machinery of <see cref="PropertyPane"/>.
        /// </remarks>
        internal PaneNode()
        {
            mPropertyTree = null;
            mPropertyPane = null;
            mbIsShared = false;
            mText = "";
            mNodes = new PaneNodeCollection(this);
            mIsDummy = true;
        }
    
        /// <summary>
        /// Create a <c>PaneNode</c> to represent a regular PropertyPane
        /// </summary>
        /// <param name="pane">
        /// The <see cref="PropertyPane"/> that will be represented by the
        /// new <c>PaneNode</c>
        /// </param>
        /// <remarks>
        /// This constructor is marked <c>internal</c> because it only exists
        /// to facilitate the generic machinery of <see cref="PropertyPane"/>.
        /// </remarks>
        internal PaneNode(PropertyPane pane)
        {
            mPropertyPane = pane;
            mText = pane.Text;

            mPaneInstanceData = null;
            mbIsShared = false;
            mNodes = new PaneNodeCollection(this);

            mPropertyPane.PaneNodeInternal = this;
        }

        /// <summary>
        ///   Create a PaneNode to represent a SharedPropertyPane
        /// </summary>
        /// <param name="sharedPaneType"></param>
        /// <param name="data"></param>
        /// <remarks>
        /// This constructor is marked <c>internal</c> because it only exists
        /// to facilitate the generic machinery of <see cref="PropertyPane"/>.
        /// </remarks>
        internal PaneNode(Type sharedPaneType, object data)
        {
            mPropertyPane = null;
            mbIsShared = true;
            mSharedPaneType = sharedPaneType;
            mPaneInstanceData = data;
            mIndex = -1;
            mNodes = new PaneNodeCollection(this);
        }

        /// <summary>
        ///   Gets a value indicating whether or not this <c>PaneNode</c> 
        ///   represents a subclass of <see cref="SharedPropertyPane">
        ///   SharedPropertyPane</see>.
        /// </summary>
        /// <value>
        ///   This value is stored at object creation time depending on
        ///   which constructor was used.
        /// </value>
        public bool IsShared
        {
            get
            {
                return mbIsShared;
            }
        }

        /// <summary>
        /// Gets the <see cref="PropertyPane">PropertyPane</see> instance
        /// that this <c>PaneNode</c> is associated with.
        /// </summary>
        /// <value>
        /// An instance of <see cref="PropertyPane">PropertyPane</see> which this
        /// <c>PaneNode</c> represents.
        /// </value>
        /// <remarks>
        /// <para>
        /// This value is guarunteed to always be non-<c>null</c>.
        /// </para>
        /// <para>
        /// If the <see cref="PropertyPane">PropertyPane</see> is actually an 
        /// instance of a <see cref="SharedPropertyPane">SharedPropertyPane</see>,
        /// more than one <c>PaneNode</c> may reference it.
        /// </para>
        /// </remarks>
        public PropertyPane PropertyPane
        {
            get
            {
                return mPropertyPane;
            }
        }

        /// <summary>
        /// Gets or sets the <see cref="PropertyPane">PropertyPane</see> instance
        /// that this <c>PaneNode</c> is associated with.
        /// </summary>
        /// <value>
        /// An instance of <see cref="PropertyPane">PropertyPane</see> which this
        /// <c>PaneNode</c> represents.
        /// </value>
        /// <remarks>
        /// <para>
        /// This value is guarunteed to always be non-<c>null</c>.
        /// </para>
        /// <para>
        /// If the <see cref="PropertyPane">PropertyPane</see> is actually an 
        /// instance of a <see cref="SharedPropertyPane">SharedPropertyPane</see>,
        /// more than one <c>PaneNode</c> may reference it.
        /// </para>
        /// </remarks>
        internal PropertyPane PropertyPaneInternal
        {
            get
            {
                return mPropertyPane;
            }
            set
            {
                mPropertyPane = value;
            }
        }
        /// <summary>
        /// Gets the user-specified data object that is associated with this particular
        /// <c>PaneNode</c>.
        /// </summary>
        /// <value>
        /// The object instance returned by this property is determined by whatever data 
        /// object the user specified when adding a <see cref="SharedPropertyPane">
        /// SharedPropertyPane</see>.
        /// </value>
        /// <remarks>
        /// <para>
        /// When <see cref="PaneNode.IsShared">IsShared</see> is <c>false</c>, 
        /// <c>PaneNode.Data</c> will always be <c>null</c>.
        /// </para>
        /// </remarks>
        public object Data
        {
            get
            {
                return mPaneInstanceData;
            }
        }

        /// <summary>
        /// Gets the index of this <c>PaneNode</c> in relation to its siblings
        /// in <see cref="PaneNode.Parent.PaneNodes">PaneNode.Parent.PaneNodes
        /// </see>.
        /// </summary>
        /// <value>
        /// <para>
        /// The value returned is the zero-based index of this <c>PaneNode</c>
        /// in <see cref="PaneNode.Parent.PaneNodes">PaneNode.Parent.PaneNodes
        /// </see>.
        /// </para>
        /// <para>
        /// A value of <c>-1</c> indicates that this <c>PaneNode</c> is not
        /// currently a child of a <see cref="PaneNodeCollection">
        /// PaneNodeCollection</see>.
        /// </para>
        /// </value>
        public int Index
        {
            get
            {
                return mIndex;
            }
        }

        /// <summary>
        /// Gets or Sets the index of this <c>PaneNode</c> in relation to
        /// its siblings in
        /// <see cref="PaneNode.Parent.PaneNodes">PaneNode.Parent.PaneNodes</see>.
        /// </summary>
        /// <value>
        /// <para>
        /// The value returned is the zero-based index of this <c>PaneNode</c>
        /// in <see cref="PaneNode.Parent.PaneNodes">PaneNode.Parent.PaneNodes
        /// </see>.
        /// </para>
        /// <para>
        /// A value of <c>-1</c> indicates that this <c>PaneNode</c> is not
        /// currently a child of a <see cref="PaneNodeCollection">
        /// PaneNodeCollection</see>.
        /// </para>
        /// </value>
        /// <remarks>
        /// <c>IndexInternal</c> is only for use by the various bookeeping functions
        /// implemented by <see cref="PaneNodeCollection">PaneNodeCollection</see>.
        /// It is semantically read-only - it is only written to in order to record
        /// the resulting index after adding the <c>PaneNode</c> to a
        /// <c>PaneNodeCollection</c>.
        /// </remarks>
        internal int IndexInternal
        {
            get
            {
                return mIndex;
            }
            set
            {
                mIndex = value;
            }
        }

        /// <summary>
        /// Gets or sets the image list index value of the image displayed when 
        /// the <c>PaneNode.TreeNode</c> is not selected in the 
        /// <see cref="PropertyTree">PropertyTree</see>.
        /// </summary>
        /// <value>
        /// <para>
        /// A zero-based index that identifies an image in the 
        /// <see cref="ImageList">ImageList</see> referenced by
        /// <see cref="PropertyTree.ImageList">PropertyTree.ImageList
        /// </see>.
        /// </para>
        /// <para>
        /// A value of <c>-1</c> indicates that no image will be displayed even 
        /// if <see cref="PropertyTree.ImageList">PropertyTree.ImageList</see>
        /// is non-<c>null</c>.
        /// </para>
        /// </value>
        /// <remarks>
        /// This value defaults to the value given by 
        /// <see cref="PropertyTree.ImageIndex">PropertyTree.ImageIndex</see>.
        /// </remarks>
        public int ImageIndex
        {
            get
            {
                return mImageIndex;
            }
            set
            {
                mImageIndex = value;
                SyncImageIndex();
            }
        }

        /// <summary>
        /// Updates <see cref="PaneNode.TreeNode.ImageIndex">
        /// PaneNode.TreeNode.ImageIndex</see> with the value given
        /// by <see cref="PaneNode.ImageIndex">PaneNode.ImageIndex</see>.
        /// </summary>
        private void SyncImageIndex()
        {
            if(TreeNode != null)
                TreeNode.ImageIndex = mImageIndex;
        }

        /// <summary>
        /// Gets or sets the image list index value of the image displayed when 
        /// the <c>PaneNode.TreeNode</c> is selected in the 
        /// <see cref="PropertyTree">PropertyTree</see>.
        /// </summary>
        /// <value>
        /// <para>
        /// A zero-based index that identifies an image in the 
        /// <see cref="ImageList">ImageList</see> referenced by
        /// <see cref="PropertyTree.ImageList">PropertyTree.ImageList
        /// </see>.
        /// </para>
        /// <para>
        /// A value of <c>-1</c> indicates that no image will be displayed even 
        /// if <see cref="PropertyTree.ImageList">PropertyTree.ImageList</see>
        /// is non-<c>null</c>.
        /// </para>
        /// </value>
        /// <remarks>
        /// This value defaults to the value given by 
        /// <see cref="PropertyTree.ImageIndex">PropertyTree.SelectedImageIndex</see>.
        /// </remarks>
        public int SelectedImageIndex
        {
            get
            {
                return mSelectedImageIndex;
            }
            set
            {
                mSelectedImageIndex = value;
                SyncSelectedImageIndex();
            }
        }

        /// <summary>
        /// Updates <see cref="PaneNode.TreeNode.SelectedImageIndex">
        /// PaneNode.TreeNode.SelectedImageIndex</see> with the value given
        /// by <see cref="PaneNode.SelectedImageIndex">
        /// PaneNode.SelectedImageIndex</see>.
        /// </summary>
        private void SyncSelectedImageIndex()
        {
            if(TreeNode != null)
                TreeNode.SelectedImageIndex = mSelectedImageIndex;
        }

        /// <summary>
        /// Gets or sets a value indicating whether or not this <c>PaneNode</c>
        /// is expanded so that its children are visible.
        /// </summary>
        /// <value>
        /// A <c>bool</c> value indicating whether or not this <c>PaneNode</c>
        /// is expanded in the <see cref="PropertyTree">PropertyTree</see>.
        /// </value>
        public bool Expanded
        {
            get
            {
                return mExpanded;
            }
            set
            {
                mExpanded = value;
                SyncExpanded();
            }
        }

        /// <summary>
        /// Gets or sets a value indicating whether or not this <c>PaneNode</c>
        /// is expanded so that its children are visible.
        /// </summary>
        /// <value>
        /// A <c>bool</c> value indicating whether or not this <c>PaneNode</c>
        /// is expanded in the <see cref="PropertyTree">PropertyTree</see>.
        /// </value>
        /// <remarks>
        /// <c>ExpandedInternal</c> is only for use by the various bookeeping functions
        /// implemented by <see cref="PropertyTree">PropertyTree</see>.  Setting 
        /// <c>ExpandedInternal</c> will not actually cause the associated
        /// <see cref="TreeNode">TreeNode</see> to expand or collapse.  It is intended
        /// to simply record the results of a user manually expanding or collapsing
        /// a node.
        /// </remarks>
        internal bool ExpandedInternal
        {
            get
            {
                return mExpanded;
            }
            set
            {
                mExpanded = value;
            }
        }

        /// <summary>
        /// Updates the <see cref="PaneNode.TreeNode">
        /// PaneNode.TreeNode</see> to reflect the value given
        /// by <see cref="PaneNode.Expanded">
        /// PaneNode.Expanded</see>.
        /// </summary>
        protected void SyncExpanded()
        {
            if(TreeNode != null)
            {
                if(Expanded)
                    TreeNode.Expand();
                else
                    TreeNode.Collapse();
            }
        }

        /// <summary>
        /// Gets or sets the text that is displayed in the 
        /// <see cref="PropertyTree">PropertyTree</see> for this <c>PaneNode</c>.
        /// </summary>
        /// <value>
        /// The value is the string that is displayed in the 
        /// <see cref="PropertyTree">PropertyTree</see>'s 
        /// <see cref="TreeView">TreeView</see>.  In addition, when this 
        /// <c>PaneNode</c> is selected, <see cref="PropertyTree"/> will also display this 
        /// string above the actual <see cref="PropertyPane">PropertyPane</see> 
        /// that this <c>PaneNode</c> represents.
        /// </value>
        public string Text
        {
            get
            {
                return mText;
            }
            set
            {
                mText = value;
                SyncText();
            }
        }

        /// <summary>
        /// Updates <see cref="PaneNode.TreeNode.Text">
        /// PaneNode.TreeNode.Text</see> with the value given
        /// by <see cref="PaneNode.Text">
        /// PaneNode.Text</see>.
        /// </summary>
        private void SyncText()
        {
            if(TreeNode != null)
                TreeNode.Text = mText;
        }

        /// <summary>
        /// The <see cref="TreeNode">TreeNode</see> that <see cref="PropertyTree">
        /// PropertyTree</see> uses to represent this <c>PaneNode</c> in its
        /// internal <see cref="TreeView">TreeView</see>.
        /// </summary>
        /// <value>
        /// <para>
        /// The <see cref="TreeNode">TreeNode</see> that <see cref="PropertyTree">
        /// PropertyTree</see> uses to represent this <c>PaneNode</c> in its
        /// internal <see cref="TreeView">TreeView</see>.
        /// </para>
        /// <para>
        /// If this <c>PaneNode</c> is not currently in a <see cref="PropertyTree"/>, this
        /// value is <c>null</c>.
        /// </para>
        /// </value>
        /// <remarks>
        /// <para>
        /// Setting this value will cause this <c>PaneNode</c> to resynchronize its
        /// various <see cref="TreeNode">TreeNode</see>-related properties, and
        /// will also cause it to add all of the <c>PaneNode</c>s in 
        /// <see cref="PaneNode.PaneNodes">PaneNodes</see> to the tree.
        /// </para>
        /// </remarks>
        internal TreeNode TreeNode
        {
            get
            {
                return mTreeNode;
            }
            set
            {
                TreeNode oldVal = mTreeNode;
                mTreeNode = value;

                if(oldVal == null && mTreeNode != null)
                {
                    foreach(PaneNode child in mNodes)
                        PropertyTree.AddPaneNodeToTree(this,child);

                    SyncExpanded();
                    SyncText();
                }
                else if(oldVal != null && mTreeNode == null)
                {
                    foreach(PaneNode child in mNodes)
                        PropertyTree.RemovePaneNodeFromTree(child);
                }
            }
        }

        /// <summary>
        /// Gets the parent <c>PaneNode</c> of this <c>PaneNode</c>
        /// </summary>
        /// <value>
        /// The parent <c>PaneNode</c> of this <c>PaneNode</c>.  This value 
        /// is <c>null</c> if this <c>PaneNode</c> has no parent.
        /// </value>
        public PaneNode Parent
        {
            get
            {
                return mParent;
            }
        }

        /// <summary>
        /// Gets or sets the parent <c>PaneNode</c> of this <c>PaneNode</c>.  This
        /// settable version is intended to be used internally.
        /// </summary>
        /// <value>
        /// <para>
        /// The parent <c>PaneNode</c> of this <c>PaneNode</c>.  This value 
        /// is <c>null</c> if this <c>PaneNode</c> has no parent.
        /// </para>
        /// </value>
        /// <remarks>
        /// <para>
        /// Other than assigning this <c>PaneNode</c> a parent, setting this
        /// value affects this <c>PaneNode</c>'s appearance in a
        /// <see cref="PropertyTree"/> according to the following rules:
        /// </para>
        /// <list type="table">
        ///     <listheader>
        ///         <term>Scenario</term>
        ///         <description>Result</description>
        ///     </listheader>
        ///     <item>
        ///         <term>
        ///         <see cref="PaneNode.Parent"/><c> == null</c>, and 
        ///         <c>value == null</c>
        ///         </term>
        ///         <description>
        ///         No action takes place
        ///         </description>
        ///     </item>
        ///     <item>
        ///         <term>
        ///         <see cref="PaneNode.Parent"/><c> == null</c>, and 
        ///         <c>value != null</c>
        ///         </term>
        ///         <description>
        ///         <see cref="PaneNode.Parent"/> is set to <c>value</c>.  <c>PaneNode</c>
        ///         is added to the <see cref="PropertyTree"/> that its parent <c>PaneNode</c>
        ///         is in (if any).
        ///         </description>
        ///     </item>
        ///     <item>
        ///         <term>
        ///         <see cref="PaneNode.Parent"/><c> != null</c>, and 
        ///         <c>value == null</c>
        ///         </term>
        ///         <description>
        ///         <see cref="PaneNode.Parent"/> is set to <c>null</c>, and is removed
        ///         from the <see cref="PropertyTree"/> that its parent <c>PaneNode</c>
        ///         is in (if any).
        ///         </description>
        ///     </item>
        ///     <item>
        ///         <term>
        ///         <see cref="PaneNode.Parent"/><c> != null</c>, and 
        ///         <c>value != null</c>
        ///         </term>
        ///         <description>
        ///         <see cref="InvalidOperationException"/> is thrown.  A <c>PaneNode</c>
        ///         must first be removed from its parent by calling its parent's
        ///         <see cref="PaneNode.PaneNodes">PaneNode.PaneNodes.</see><see cref="PaneNodeCollection.Remove">Remove</see>.
        ///         </description>
        ///     </item>
        /// </list>
        /// </remarks>
        /// <exception cref="InvalidOperationException">
        ///     Thrown if a <c>PaneNode</c> is assigned to a parent <c>PaneNode</c> even 
        ///     though it is already the child of another <c>PaneNode</c>.
        /// </exception>
        internal PaneNode ParentInternal
        {
            get
            {
                return mParent;
            }
            set
            {
                PaneNode oldVal = mParent;
                PaneNode newVal = value;

                if(newVal == null)
                {
                    if(oldVal != null)
                    {
                        if(IsInTree)
                            oldVal.PropertyTree.RemovePaneNodeFromTree(this);
                        mParent = value;
                    }
                }
                else if(newVal != null)
                {
                    mParent = value;
                    if(newVal.IsInTree && PropertyTree != null && !PropertyTree.IsInitializing)
                        newVal.PropertyTree.AddPaneNodeToTree(newVal,this);
                }
                else if(oldVal != null && newVal != null)
                    throw new InvalidOperationException(
                        "Attempted to set PaneNode.TreeNode to a non-null value when " +
                        "it was already set at a non-null value.  You must manually " + 
                        "remove the PaneNode from its PaneNodeCollection before you can " + 
                        "add it to another one.");
            }
        }

        /// <summary>
        /// Gets the <see cref="PaneNodeCollection"/> that holds the this <c>PaneNode</c>'s
        /// child <c>PaneNode</c>s
        /// </summary>
        /// <value>
        /// A reference to the <see cref="PaneNodeCollection"/> that holds 
        /// this <c>PaneNode</c>'s child <c>PaneNode</c>s
        /// </value>
        public PaneNodeCollection PaneNodes
        {
            get
            {
                return mNodes;
            }
        }

        /// <summary>
        /// Gets a reference to the <see cref="PropertyTree"/> to which this
        /// <c>PaneNode</c> ultimately belongs.
        /// </summary>
        /// <value>
        /// A reference to the <see cref="PropertyTree"/> to which this
        /// <c>PaneNode</c> ultimately belongs.  This value can be <c>null</c>
        /// if this <c>PaneNode</c> is not in a <see cref="PropertyTree"/> at the
        /// moment.
        /// </value>
        public PropertyTree PropertyTree
        {
            get
            {
                if(mPropertyTree != null)
                    return mPropertyTree;
                else if(Parent != null)
                    return Parent.PropertyTree;
                else
                    return null;
            }
        }

        /// <summary>
        /// Gets a <see cref="Type"/> instance representing the subclass of
        /// <see cref="SharedPropertyPane"/> represented by this <c>PaneNode</c>
        /// </summary>
        /// <value>
        /// A <see cref="Type"/> instance representing the subclass of
        /// <see cref="SharedPropertyPane"/> represented by this <c>PaneNode</c>.  This
        /// value is <c>null</c> if the <c>PaneNode</c> does not represent an instance of
        /// a class derived from <see cref="SharedPropertyPane"/>.
        /// </value>
        public Type SharedPaneType
        {
            get
            {
                return mSharedPaneType;
            }
        }

        /// <summary>
        /// Gets a boolean value indicating whether or not this <c>PaneNode</c> is
        /// actually represented in the <see cref="TreeView"/> of a 
        /// <see cref="PropertyTree"/>
        /// </summary>
        /// <value>
        /// A boolean value indicating whether or not this <c>PaneNode</c> is
        /// actually represented in the <see cref="TreeView"/> of a 
        /// <see cref="PropertyTree"/>.
        /// </value>
        internal bool IsInTree
        {
            get
            {
                return (TreeNode != null) || (mPropertyTree != null);
            }
        }
  
        /// <summary>
        ///   Gets a boolean value that indicates whether or not this <c>PaneNOde</c> 
        ///   is selected.
        /// </summary>
        /// <value>
        ///   A boolean value that indicates whether or not this <c>PaneNOde</c> 
        ///   is selected.
        /// </value>
        public bool Selected 
        {
            get 
            {
                if(PropertyTree != null)
                    return (PropertyTree.SelectedPaneNode == this);
                else
                    return false;
            }
        }

        /// <summary>
        /// Gets a boolean value indicating whether or not this node is a dummy-node.
        /// </summary>
        /// <value>
        /// Gets a boolean value indicating whether or not this node is a dummy-node.
        /// </value>
        /// <remarks>
        /// A "dummy" node is provided for internal use - mostly for shuffling 
        /// <c>PaneNode</c>s around behind the scenes.
        /// </remarks>
        internal bool IsDummy
        {
            get
            {
                return mIsDummy;
            }
        }

    #region Implementation of IComparable
        
        /// <summary>
        /// Compares this <c>PaneNode</c> to another <c>PaneNode</c>
        /// </summary>
        /// <param name="other">
        /// A reference to another <c>PaneNode</c> object.
        /// </param>
        /// <returns>
        /// <list type="table">
        ///     <listheader>
        ///         <term>
        ///             Return value
        ///         </term>
        ///         <description>
        ///             Meaning
        ///         </description>
        ///     </listheader>
        ///     <item>
        ///         <term>
        ///             <c>&lt; 0</c>
        ///         </term>
        ///         <description>
        ///             Indicates this <c>PaneNode</c> is "less" than the 
        ///             <paramref name="other"/> <c>PaneNode</c>
        ///         </description>
        ///     </item>
        ///     <item>
        ///         <term>
        ///             <c>0</c>
        ///         </term>
        ///         <description>
        ///             Indicates this <c>PaneNode</c> is "equal to" the 
        ///             <paramref name="other"/> <c>PaneNode</c>
        ///         </description>
        ///     </item>
        ///     <item>
        ///         <term>
        ///             <c>&gt; 0</c>
        ///         </term>
        ///         <description>
        ///             Indicates this <c>PaneNode</c> is "greater than" the 
        ///             <paramref name="other"/> <c>PaneNode</c>
        ///         </description>
        ///     </item>
        /// </list>
        /// </returns>
        public int CompareTo(object other)
        {
            PaneNode otherPaneNode = (PaneNode)other;

            return Index-otherPaneNode.Index;
        }
    #endregion
    }
}
